#include <retro.h>
#include "retro.library.h"

using namespace Retro::Data;

DataManager::DataManager()
{
  mBuffer.setSize(100);

  memset(
    (PVOID)mBuffer.getBuffer(),
    0,
    sizeof(StoredData) * mBuffer.getSize());
}

DataManager::~DataManager()
{
  for (UINT i = 0; i < mBuffer.getLength(); ++i)
  {
    if (mBuffer[i].type == DataString)
      delete[] mBuffer[i].data.string;
  }
}

BOOL DataManager::save(PCTSTR iPath)
{
  BOOL wResult = TRUE;

  HANDLE wFile = CreateFile(
    iPath,
    GENERIC_WRITE,
    0,
    NULL,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

  if (wFile == INVALID_HANDLE_VALUE)
  {
    wResult = FALSE;
  }
  else
  {
    DWORD wWritten;

    for (UINT i = 0; i < mBuffer.getSize(); ++i)
    {
      WriteFile(
        wFile,
        &mBuffer[i].type,
        sizeof(mBuffer[i].type),
        &wWritten,
        NULL);

      if (mBuffer[i].type == DataString)
      {
        UINT wStringLength = (UINT)strlen(mBuffer[i].data.string);

        WriteFile(
          wFile,
          &wStringLength,
          sizeof(wStringLength),
          &wWritten,
          NULL);

        if (wStringLength)
        {
          if (!IO::WriteBuffer(
            wFile,
            mBuffer[i].data.string,
            wStringLength * sizeof(CHAR)))
          {
            wResult = FALSE;
            break;
          }
        }
      }
      else
      {
        WriteFile(
          wFile,
          &mBuffer[i].data,
          sizeof(mBuffer[i].data),
          &wWritten,
          NULL);
      }
    }

    CloseHandle(wFile);
  }

  return wResult;
}

BOOL DataManager::load(PCTSTR iPath)
{
  BOOL wResult = TRUE;

  HANDLE wFile = CreateFile(
    iPath,
    GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

  if (wFile == INVALID_HANDLE_VALUE)
  {
    wResult = FALSE;
  }
  else
  {
    BOOL wCanRead = TRUE;
    StoredData wData;
    DWORD wRead;

    mBuffer.clear();

    while (1)
    {
      memset(&wData, 0, sizeof(wData));

      if (!ReadFile(
        wFile,
        &wData.type,
        sizeof(wData.type),
        &wRead,
        NULL) ||
        wRead != sizeof(wData.type))
      {
        break;
      }

      if (wData.type == DataString)
      {
        UINT wStringLength;

        if (!ReadFile(
          wFile,
          &wStringLength,
          sizeof(wStringLength),
          &wRead,
          NULL) ||
          wRead != sizeof(wStringLength))
        {
          break;
        }

        if (wStringLength)
        {
          wData.data.string = new CHAR[wStringLength + 1];
          wData.data.string[wStringLength] = '\0';

          if (!IO::ReadBuffer(
            wFile,
            wData.data.string,
            wStringLength * sizeof(CHAR)))
          {
            delete[] wData.data.string;

            wResult = FALSE;
            break;
          }
        }
      }
      else
      {
        if (!ReadFile(
          wFile,
          &wData.data,
          sizeof(wData.data),
          &wRead,
          NULL) ||
          wRead != sizeof(wData.data))
        {
          break;
        }
      }

      mBuffer.add(wData);
    }

    CloseHandle(wFile);
  }

  return wResult;
}

VOID DataManager::setSize(UINT iValue)
{
  for (UINT i = iValue; i < mBuffer.getSize(); ++i)
  {
    if (mBuffer[i].type == DataString)
      delete[] mBuffer[i].data.string;
  }

  UINT wOldSize = mBuffer.getSize();

  mBuffer.setSize(iValue);

  if (mBuffer.getSize() > wOldSize)
  {
    memset(
      (PVOID)(mBuffer.getBuffer() + wOldSize),
      0,
      sizeof(StoredData) * (mBuffer.getSize() - wOldSize));
  }
}

VOID DataManager::setString(UINT iIndex, PCSTR iValue)
{
  if (mBuffer[iIndex].type == DataString)
    delete[] mBuffer[iIndex].data.string;

  INT wLength = (INT)strlen(iValue) + 1;

  mBuffer[iIndex].data.string = new CHAR[wLength];

  memcpy(
    mBuffer[iIndex].data.string,
    iValue,
    wLength * sizeof(CHAR));

  mBuffer[iIndex].type = DataString;
}

VOID DataManager::setInt(UINT iIndex, LONG iValue)
{
  if (mBuffer[iIndex].type == DataString)
    delete[] mBuffer[iIndex].data.string;

  mBuffer[iIndex].data.integer = iValue;
  mBuffer[iIndex].type = DataInteger;
}

VOID DataManager::setReal(UINT iIndex, DOUBLE iValue)
{
  if (mBuffer[iIndex].type == DataString)
    delete[] mBuffer[iIndex].data.string;

  mBuffer[iIndex].data.real = iValue;
  mBuffer[iIndex].type = DataReal;
}
